import os
import shutil

from script.TelewebDownloader import TelewebDownloader
from script.server.ftp.FtpServer import FtpServer
from script.server.Servers import Servers
from script.server.teleweb.TelewebServer import TelewebServer
from script.util.ProgressBar import ProgressBar
from script.util.Print import Print
from script.util.FileLog import FileLog


class SyncFromTelewebToFtp(object):
    def __init__(self, src_server: str, src_path: str, dst_server: str, dst_path: str, log: FileLog = None):
        self.mSrcServerName = src_server
        self.mDstServerName = dst_server
        self.mSrcPath = src_path.replace('\\', '/')
        self.mDstPath = dst_path.replace('\\', '/')

        self.mSrcServer: TelewebServer = Servers.create_server(src_server)
        self.mSrcDownloader = TelewebDownloader(self.mSrcServer)
        self.mSrcDownloader.cd(self.mSrcPath)

        self.mDstServer: FtpServer = Servers.create_server(dst_server)
        self.mDstServer.mkd(self.mDstPath)
        self.mDstServer.cd(self.mDstPath)

        # get log dir & path
        self.mLog = log

    def log(self, msg: str):
        if self.mLog:
            self.mLog.log(msg)

    def total_size(self, path: str) -> int:
        if not os.path.exists(path):
            return 0
        elif os.path.isdir(path):
            size: int = 0
            for filename in os.listdir(path):
                size += self.total_size('%s/%s' % (path, filename))
            return size
        else:
            return os.path.getsize(path)

    def sync_all(self):
        files = self.mSrcDownloader.ls_filename()

        for file in files:
            SyncFromTelewebToFtp(self.mSrcServerName, os.path.join(self.mSrcPath, file),
                                 self.mDstServerName, os.path.join(self.mDstPath, file),
                                 self.mLog).sync_dir().close()

        return self

    def sync_file(self):
        self.log('==== Sync Begin ====')
        self.log('= start sync from [%s] to [%s]' % (self.mSrcPath, self.mDstPath))

        Print.green('=============================').edl()
        Print.green('= start sync from [%s] to [%s]' % (self.mSrcPath, self.mDstPath)).edl()

        # get teleweb image list
        teleweb_files = [self.mSrcDownloader.pwd(), ]
        # teleweb_files = self.mTeleweb.ls_filename()
        # print(teleweb_files)

        # get ftp image list
        ftp_files_info = self.mDstServer.ls_info()
        ftp_files = []
        for file_info in ftp_files_info:  # remove non-synced files
            if file_info[1]:
                if '%s/synced' % file_info[0] in self.mDstServer.ls(file_info[0]):
                    ftp_files.append(file_info[0])
        # print(ftp_files)

        # get images to upload
        upload_images = list(set(teleweb_files) - set(ftp_files))
        upload_images.sort()
        Print.green('Images to upload: %s' % upload_images).edl()

        # start sync
        for image in upload_images:
            # check is sw like
            self.mSrcDownloader.cd('%s/%s' % (self.mSrcPath, image))
            # if not self.mTeleweb.is_sw_like():
            #    Print.yellow('>> Ignore invalid image [%s]' % image).edl()
            #    # self.log('>> Ignore invalid image [%s]' % image)
            #    continue

            # download from teleweb to cache
            Print.green('>> Downloading %s from teleweb' % image).edl()
            downloaded_path = self.mSrcDownloader.download(True)
            result = downloaded_path is not None
            if result:
                Print.green('>> Downloading %s from teleweb. Done' % image).edl()
            else:
                Print.red('>> Downloading %s from teleweb. Failed' % image).edl()
                continue

            # upload from cache to ftp
            Print.green('>> Uploading %s to ftp' % image).edl()
            total_upload_size: int = self.total_size(downloaded_path)
            if total_upload_size <= 0:
                Print.yellow('Nothing to update. Ignore it').edl()
                continue

            upload_path = '%s/%s' % (self.mDstPath, image)
            progress = ProgressBar(100, Print.BLUE, Print.YELLOW, Print.BLACK, False)
            progress.begin()
            progress.set(0, total_upload_size, 'Uploading to %s ...' % upload_path)

            def upload_progress(cur_size: int):
                nonlocal upload_path
                progress.set(cur_size, total_upload_size, 'Uploading to %s ...' % upload_path)

            result = self.mDstServer.upload(downloaded_path, image, upload_progress)
            if result:
                self.mDstServer.cd(image)
                self.mDstServer.set_synced()
                self.mDstServer.cd('..')
                progress.set(total_upload_size, total_upload_size, 'Done at %s' % upload_path)
                progress.end()
                Print.green('>> Uploading %s to ftp. Done' % image).edl()
            else:
                progress.set(total_upload_size, total_upload_size, 'Failed at %s' % upload_path)
                progress.end()
                Print.red('>> Uploading %s to ftp. Failed' % image).edl()

            # remove cache
            if result:
                shutil.rmtree(downloaded_path)
                Print.green('>> Sync image %s Done' % image).edl()
                self.log('>> Sync [%s] Done' % image)
            else:
                Print.red('>> Sync image %s Failed' % image).edl()
                self.log('>> Sync [%s] Failed' % image)

        Print.green('= All Sync from [%s] to [%s] done!!' % (self.mSrcPath, self.mDstPath)).edl()
        Print.green('=============================').edl()

        self.log('==== Sync End ====')
        return self

    def sync_dir(self):
        self.log('==== Sync Begin ====')
        self.log('= start sync from [%s] to [%s]' % (self.mSrcPath, self.mDstPath))

        Print.green('=============================').edl()
        Print.green('= start sync from [%s] to [%s]' % (self.mSrcPath, self.mDstPath)).edl()

        # get teleweb image list
        teleweb_files = self.mSrcDownloader.ls_filename()
        # print(teleweb_files)

        # get ftp image list
        ftp_files_info = self.mDstServer.ls_info()
        ftp_files = []
        for file_info in ftp_files_info:  # remove non-synced files
            if file_info[1]:
                if '%s/synced' % file_info[0] in self.mDstServer.ls(file_info[0]):
                    ftp_files.append(file_info[0])
        # print(ftp_files)

        # get images to upload
        upload_images = list(set(teleweb_files) - set(ftp_files))
        upload_images.sort()
        Print.green('Images to upload: %s' % upload_images).edl()

        # start sync
        for image in upload_images:
            # check is sw like
            self.mSrcDownloader.cd('%s/%s' % (self.mSrcPath, image))
            # if not self.mTeleweb.is_sw_like():
            #    Print.yellow('>> Ignore invalid image [%s]' % image).edl()
            #    # self.log('>> Ignore invalid image [%s]' % image)
            #    continue

            # download from teleweb to cache
            Print.green('>> Downloading %s from teleweb' % image).edl()
            downloaded_path = self.mSrcDownloader.download(True)
            result = downloaded_path is not None
            if result:
                Print.green('>> Downloading %s from teleweb. Done' % image).edl()
            else:
                Print.red('>> Downloading %s from teleweb. Failed' % image).edl()
                continue

            # upload from cache to ftp
            Print.green('>> Uploading %s to ftp' % image).edl()
            total_upload_size: int = self.total_size(downloaded_path)
            if total_upload_size <= 0:
                Print.yellow('Nothing to upload. Ignore it').edl()
                continue

            upload_path = '%s/%s' % (self.mDstPath, image)
            progress = ProgressBar(100, Print.BLUE, Print.YELLOW, Print.BLACK, False)
            progress.begin()
            progress.set(0, total_upload_size, 'Uploading to %s ...' % upload_path)

            def upload_progress(cur_size: int):
                nonlocal upload_path
                progress.set(cur_size, total_upload_size, 'Uploading to %s ...' % upload_path)

            result = self.mDstServer.upload(downloaded_path, image, upload_progress)
            if result:
                self.mDstServer.cd(image)
                self.mDstServer.set_synced()
                self.mDstServer.cd('..')
                progress.set(total_upload_size, total_upload_size, 'Done at %s' % upload_path)
                progress.end()
                Print.green('>> Uploading %s to ftp. Done' % image).edl()
            else:
                progress.set(total_upload_size, total_upload_size, 'Failed at %s' % upload_path)
                progress.end()
                Print.red('>> Uploading %s to ftp. Failed' % image).edl()

            # remove cache
            if result:
                shutil.rmtree(downloaded_path)
                Print.green('>> Sync image %s Done' % image).edl()
                self.log('>> Sync [%s] Done' % image)
            else:
                Print.red('>> Sync image %s Failed' % image).edl()
                self.log('>> Sync [%s] Failed' % image)

        Print.green('= All Sync from [%s] to [%s] done!!' % (self.mSrcPath, self.mDstPath)).edl()
        Print.green('=============================').edl()

        self.log('==== Sync End ====')
        return self

    def close(self):
        self.mDstServer.quit()
